/*
Author ShawJay
使用时，建议将counter改为pkg目录下文件，供其他模块引用
即author只可以通过new相应函数使用,保证内部不可见,防止误用函数导致出错

目前在初始化的时候,如果遇到相同key的,重置时间的问题,仍在考虑中,主要是map的并发读写问题

*/

package counter

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type counter struct {
	ctx   context.Context
	exit  context.CancelFunc
	m     map[string]int
	mutex sync.Mutex
	clear chan func()
}

func NewCounter() *counter {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	c := counter{
		m:     make(map[string]int),
		clear: make(chan func()),
		ctx:   ctx,
		exit:  cancel,
	}
	go func() {
		c.init()
	}()
	return &c
}

func (c *counter) Exit() {
	c.exit()
	fmt.Println("counter2 will exit after 1s")
	time.Sleep(1*time.Second)
}

func (c *counter) init() {
	for {
		select {
		case clear := <-c.clear:
			{
				go func() {
					clear()
				}()
			}
		}
	}
}

func (c *counter) Query(key string) int {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if _, ok := c.m[key]; ok {
		return c.m[key]
	}
	return -1
}

func (c *counter) Cnt(key string, cnt int) {
	if c.Query(key) != -1 {
		c.mutex.Lock()
		defer c.mutex.Unlock()
		c.m[key] += cnt
	} else {
		fmt.Println("key not exist or not init")
	}
}

func (c *counter) InitIncr(duration int, key string) {
	if c.Query(key) == -1 {
		c.mutex.Lock()
		defer c.mutex.Unlock()
		c.m[key] = 0
		clear := func() {
		loop:
			for {
				select {
				case <-time.After(time.Duration(duration) * time.Millisecond):
					{
						c.mutex.Lock()
						c.m[key] = 0
						c.mutex.Unlock()
					}
				case <-c.ctx.Done():
					{
						break loop
					}
				}
			}
			fmt.Println("exist clear")
		}
		c.clear <- clear
	} else {
		fmt.Println("key has been existed, you may need a new Counter or use exit")
	}
}
